home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-08-27 | 11.3 KB | 276 lines | [TEXT/PJMM] |
- {******************************************************************************}
- { StandardGetFolder.c }
- { }
- { This little chunk o' code implements a way to let the user choose a }
- { folder to save files in via a StandardFile Dialog. }
- { }
- { Since the code uses the CustomGetFile function and depends on the use of }
- { FSSpec records, it only works under System 7.0 or later. }
- { }
- { And don't forget to include the custom dialog resources ( a 'DITL' and }
- { 'DLOG') in your project. }
- { }
- { Portions of this code were originally provided by Paul Forrester }
- { (paulf@apple.com) to the think-c internet mailing list in response to my }
- { my question on how to do exactly what this code does. I've added a }
- { couple of features, such as the ability to handle aliased folders and }
- { the programmer definable prompt. I also cleaned and tightened the code, }
- { stomped a couple of bugs, and packaged it up neatly. Bunches of work, }
- { but I learned A LOT about Standard File, the File Manager, the Dialog }
- { Manager, and the Alias Manager. I tried to include in the comments some }
- { of the neat stuff I discovered in my hours of pouring over Inside Mac. }
- { Hope you find it educational as well as useful. }
- {******************************************************************************}
- { Converted to Pascal by Peter N Lewis <peter.lewis@info.curtin.edu.au> Dec 1992 }
-
- unit StandardGetFolder;
-
- interface
-
- procedure GetSFLocation (var vrn: integer; var dirID: longInt);
- procedure SetSFLocation (vrn: integer; dirID: longInt);
- procedure StandardGetFolder (where: Point; message: Str255; var mySFReply: StandardFileReply);
-
- implementation
-
- uses
- Aliases, Script;
-
- { Resource IDs }
- const
- rGetFolderButton = 10;
- rGetFolderMessage = 11;
- rGetFolderSelectString = 12;
- kFolderBit = $0010;
- rGetFolderDialog = 2008;
-
- { Global Variables }
-
- var
- gCurrentSelectedFolder: str255;
-
- const
- SFSaveDiskA = $214;
- CurDirStoreA = $398;
- type
- intPtr = ^integer;
- longPtr = ^longInt;
-
- { The following set of routines are used to access a couple of low memory }
- { globals that are necessary when extending Standard File. One example is }
- { trying to get the current directory while in a file filter. These routines }
- { were used to bottleneck all the low memory usage. If the system one day }
- { supports them with a trap call, then we can easily update these routines. }
-
- procedure GetSFLocation (var vrn: integer; var dirID: longInt);
- begin
- vrn := -intPtr(SFSaveDiskA)^;
- dirID := longPtr(CurDirStoreA)^;
- end;
-
- procedure SetSFLocation (vrn: integer; dirID: longInt);
- begin
- intPtr(SFSaveDiskA)^ := -vrn;
- longPtr(CurDirStoreA)^ := dirID;
- end;
-
- {******************************************************************************}
- { MyCustomGetDirectoryFileFilter }
- { }
- { This is the file filter passed to CustomGetFile. It passes folders only. }
- {******************************************************************************}
- function MyCustomGetDirectoryFileFilter (var myPB: CInfoPBRec; myDataPtr: Ptr): boolean;
- begin
- MyCustomGetDirectoryFileFilter := BAND(myPB.ioFlAttrib, kFolderBit) = 0;
- end;
-
-
- {******************************************************************************}
- { MyCustomGetDirectoryDlogHook }
- { }
- { This function lets us process item hits in the GetFolderDialog. We're }
- { only interested if the user hit the selectFolder button. We pass all }
- { other item hits back to ModalDialog. }
- {******************************************************************************}
-
- function MyCustomGetDirectoryDlogHook (item: integer; theDialog: DialogPtr; myDataPtr: Ptr): integer;
-
- procedure SetButtonTitle (name: Str255);
- var
- resultCode: integer;
- width: integer;
- TmpStr, left, right: str255;
- itemType: integer;
- itemHandle: handle;
- itemRect: rect;
- p: integer;
- begin
- if gCurrentSelectedFolder <> name then begin
- GetDItem(theDialog, rGetFolderSelectString, itemType, itemHandle, itemRect);
- GetIText(itemHandle, TmpStr);
- p := Pos('^1', TmpStr);
- left := copy(TmpStr, 1, p - 1);
- right := copy(TmpStr, p + 2, 255);
- GetDItem(theDialog, rGetFolderButton, itemType, itemHandle, itemRect);
- gCurrentSelectedFolder := name;
-
- {*-------------------------------------------------------------------------}
- { Find the width left over in the button after drawing the word 'Select' }
- { the quotation marks. Truncate the new name to this length. }
- {-------------------------------------------------------------------------*}
- width := (itemRect.right - itemRect.left) - StringWidth(concat(' ', left, right, ' '));
-
- resultCode := TruncString(width, name, smTruncEnd);
- if resultCode < 0 then
- ;
-
- TmpStr := concat(left, name, right);
- SetCTitle(ControlHandle(itemHandle), TmpStr);
- ValidRect(itemRect);
- end;
- end;
-
- procedure SetFolderButtonTitle (vrn: integer; dirID: longInt);
- var
- name: str63;
- pb: CInfoPBRec;
- oe: OSErr;
- begin
- pb.ioNamePtr := @name;
- pb.ioVRefNum := vrn;
- pb.ioDirID := dirID;
- pb.ioFDirIndex := -1;
- oe := PBGetCatInfoSync(@pb);
-
- if oe = noErr then begin
- SetButtonTitle(name);
- end;
- end;
-
- type
- StandardFileReplyPtr = ^StandardFileReply;
- var
- pb: CInfoPBRec;
- err: OSErr;
- itemType: integer;
- itemRect: Rect;
- itemHandle: Handle;
- mySFRPtr: StandardFileReplyPtr;
- begin
-
- {*-------------------------------------------------------------------------}
- { CustomGet calls dialog hook for both main and subsidiary dialog boxes. }
- { Make sure that dialog record indicates that this is the main GetFolder }
- { dialog. }
- {-------------------------------------------------------------------------*}
- if OSType(WindowPeek(theDialog)^.refCon) = sfMainDialogRefCon then begin
-
- mySFRPtr := StandardFileReplyPtr(myDataPtr);
-
- if item = sfHookFirstCall then begin
-
- {*-----------------------------------------------------------------}
- { Set the prompt displayed above the file list... }
- {-----------------------------------------------------------------*}
- GetDItem(theDialog, rGetFolderMessage, itemType, itemHandle, itemRect);
- SetIText(itemHandle, gCurrentSelectedFolder);
- gCurrentSelectedFolder := '';
-
- end
- else begin
- { DebugStr(StringOf(ord(mySFRPtr^.sfIsFolder) <> 0, '"', mySFRPtr^.sfFile.name, '"', ';g'));}
- if (mySFRPtr^.sfFile.name = '') then begin
- GetSFLocation(mySFRPtr^.sfFile.vRefNum, mySFRPtr^.sfFile.parID); { these aren't always set properly }
- mySFRPtr^.sfFile.name := '';
- SetFolderButtonTitle(mySFRPtr^.sfFile.vRefNum, mySFRPtr^.sfFile.parID);
- end
- else begin
- SetButtonTitle(mySFRPtr^.sfFile.name);
- end;
- end;
-
- if item = rGetFolderButton then begin
- item := sfItemCancelButton;
- mySFRPtr^.sfGood := true;
- end;
-
- end;
- MyCustomGetDirectoryDlogHook := item;
- end;
-
-
- {******************************************************************************}
- { StandardGetFolder }
- { }
- { The StandardGetFolder function. You pass it the point where you want the }
- { standard file dialog box drawn, the prompt to display above the file }
- { list, and a pointer to an StandardFileReply record. }
- { }
- { Upon return, the sfFile field of the SFReply record contains the volume }
- { reference number and directory ID that specify the folder the user }
- { chose. It also passes back the name of the chosen folder. The sfGood }
- { field is set to true if the user chose a folder, or false if not. }
- {******************************************************************************}
-
- procedure StandardGetFolder (where: Point; message: Str255; var mySFReply: StandardFileReply);
- var
- theTypeList: SFTypeList;
- myModalFilter: ProcPtr;
- pb: CInfoPBRec;
- err: OSErr;
- theItem: integer;
- isfolder, wasaliased: boolean;
- oe: OSErr;
- fs: FSSpec;
- begin
- {*-------------------------------------------------------------------------}
- { Copy the prompt to be displayed above the file list into gCurrentSelectedFolder }
- { When MyCustomGetDirectoryDlogHook is called for }
- { the first time, it will use this info to draw the prompt. }
- {-------------------------------------------------------------------------*}
- gCurrentSelectedFolder := message;
-
- {*-------------------------------------------------------------------------}
- { Call CustomGetFile. Pass it a pointer to the file filter and dialog }
- { hook functions. Also pass a pointer to mySFReply in the user data field. }
- {-------------------------------------------------------------------------*}
- CustomGetFile(@MyCustomGetDirectoryFileFilter, -1, theTypeList, mySFReply, rGetFolderDialog, where, @MyCustomGetDirectoryDlogHook, nil, nil, nil, @mySFReply);
-
- {*-------------------------------------------------------------------------}
- { Ok, now the reply record contains the volume reference number and the }
- { name of the selected folder. We need to use PBGetCatInfo to get the }
- { directory ID of the selected folder. }
- {-------------------------------------------------------------------------*}
- if mySFReply.sfGood then begin { Don't call PBGetCatInfo on cancel! }
-
- if mySFReply.sfFile.name <> '' then begin
- oe := ResolveAliasFile(mySFReply.sfFile, true, isfolder, wasaliased);
- if (oe = noErr) & not isfolder then
- DebugStr('Not folder?');
- if oe = noErr then begin
- pb.ioVRefNum := mySFReply.sfFile.vRefNum;
- pb.ioDirID := mySFReply.sfFile.parID;
- pb.ioNamePtr := @mySFReply.sfFile.name;
- pb.ioFDirIndex := 0;
-
- oe := PBGetCatInfoSync(@pb);
- end;
- mySFReply.sfGood := oe = noErr;
-
- mySFReply.sfFile.parID := pb.ioDrDirID;
- mySFReply.sfFile.name := '';
- end;
- { DebugStr(StringOf(oe, mySFReply.sfGood, mySFReply.sfFile.vRefNum, mySFReply.sfFile.parID, ';g'));}
- if oe = noErr then begin
- pb.ioVRefNum := mySFReply.sfFile.vRefNum;
- pb.ioDirID := mySFReply.sfFile.parID;
- pb.ioNamePtr := @mySFReply.sfFile.name;
- pb.ioFDirIndex := -1;
- oe := PBGetCatInfoSync(@pb);
- end;
- { DebugStr(StringOf(oe, mySFReply.sfFile.vRefNum, mySFReply.sfFile.parID, '"', mySFReply.sfFile.name, '"', ';g'));}
- end;
-
- end;
-
- end.